package com.smm.web.vmc.service.impl;

import com.smm.web.vmc.dao.BaseDao;
import com.smm.web.vmc.domain.Camera;
import com.smm.web.vmc.domain.Receipt;
import com.smm.web.vmc.domain.Tag;
import com.smm.web.vmc.domain.relation.CameraReceiptRelation;
import com.smm.web.vmc.dto.CameraDto;
import com.smm.web.vmc.service.CameraService;
import com.smm.web.vmc.service.ReceiptService;
import com.smm.web.vmc.service.TagService;
import com.smm.web.vmc.service.WarehouseService;
import com.smm.web.vmc.tool.GetImage;
import com.smm.web.vmc.util.HCNetSDK;
import com.smm.web.vmc.util.HCNetSDKInit;
import com.smm.web.vmc.util.YSApi;
import com.sun.jna.NativeLong;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by zhenghao on 2016/9/6.
 *
 */
@Slf4j
@Service
public class CameraServiceImpl implements CameraService {


    @Resource
    private BaseDao<Camera> cameraBaseDao;

    @Resource
    private BaseDao<CameraReceiptRelation> cameraReceiptRelationBaseDao;

    @Resource
    private TagService tagService;


    @Resource
    private WarehouseService warehouseService;


    @Resource
    private ReceiptService receiptService;


    @Value("${image.web.host}")
    private String imageHost;         //图片访问虚拟路径

    @Value("${image.save.path}")
    private String imageSavePath;    //抓拍图片保存路径


    @Override
    public List<Camera> getAll() {


        return cameraBaseDao.getAll(Camera.class);

    }

    @Override
    public Camera getOneById(int cameraId) {

        if(cameraId==0) return null;

        return cameraBaseDao.getOne(Camera.class,cameraId);
    }

    @Override
    public List<Camera> getAllByReceipt(String repNo) {

        DetachedCriteria where = DetachedCriteria.forClass(CameraReceiptRelation.class);
        where.add(Restrictions.eq("receipt.no",repNo));

        List<CameraReceiptRelation> relations = cameraReceiptRelationBaseDao.query(where);

        //如果没有关联结果，返回null
        if(relations==null || relations.size()==0) return null;

        //抽取摄像头对象列表
        return relations.stream().map(CameraReceiptRelation::getCamera).collect(Collectors.toList());

    }

    @Override
    public List<Camera> getAllByWarehouse(int warehouseId) {

        DetachedCriteria where = DetachedCriteria.forClass(Camera.class);
        where.add(Restrictions.eq("warehouse.id",warehouseId));
        where.addOrder(Order.desc("id"));

        return cameraBaseDao.query(where);
    }

    @Override
    public void add(CameraDto cameraDto) throws Exception {

        Camera camera = new Camera();

        BeanUtils.copyProperties(cameraDto,camera);

        camera.setWarehouse(warehouseService.getOneById(cameraDto.getWarehouseId()));

        cameraBaseDao.add(camera);

    }

    @Override
    public void update(CameraDto cameraDto) throws Exception {

        Camera camera = cameraBaseDao.getOne(Camera.class,cameraDto.getId());

        camera.setName(cameraDto.getName());
        camera.setCoverImageUrl(cameraDto.getCoverImageUrl());
        camera.setIp(cameraDto.getIp());
        camera.setWebPort(cameraDto.getWebPort());
        camera.setSeverPort(cameraDto.getSeverPort());

        camera.setAccount(cameraDto.getAccount());
        camera.setPassword(cameraDto.getPassword());
        camera.setSerialNumber(cameraDto.getSerialNumber());
        camera.setM3u8(cameraDto.getM3u8());

        cameraBaseDao.update(camera);

    }

    @Override
    public void deleteById(int id) throws Exception {

        //检查摄像头是否有关联仓单，如果有，不能删除
        DetachedCriteria where = DetachedCriteria.forClass(CameraReceiptRelation.class);
        where.add(Restrictions.eq("camera.id",id));

        List<CameraReceiptRelation> relations = cameraReceiptRelationBaseDao.query(where);

        //如果有关联关系，抛出异常
        if(relations!=null && relations.size()>0) throw  new Exception("有关联仓单，不能删除");

        //检查摄像头是否有关联标签，如果有，不能删除
        List<Tag> tagList = tagService.getAllByCamer(id);

        if(tagList!=null && tagList.size()>0) throw new Exception("有关联的RFID，不能删除");

        //删除摄像头
        cameraBaseDao.delete(cameraBaseDao.getOne(Camera.class,id));

    }

    @Override
    public String capture(Camera camera) throws Exception {

        //定义图片名称
        String imageName = String.valueOf(new Date().getTime()) + ".jpg";

        HCNetSDK hCNetSDK=null;

        NativeLong lUserID = null;

        try {
            hCNetSDK = HCNetSDKInit.newInstance();

            boolean m_bInitSDK = hCNetSDK.NET_DVR_Init();

            if (!m_bInitSDK) {
                log.info("SDK初始化失败,请检查SDK路径是否正确.");
                throw new Exception("sdk 初始化失败");
            }

            lUserID = new NativeLong();// 用户句柄

            log.info("lUserID.longValue:"+lUserID.longValue());
            /**
             * 注册之前先注销已注册的用户
             */
            if (lUserID.longValue() > -1) {
                log.info(camera.getIp()+"注册之前先注销已注册的用户");
                hCNetSDK.NET_DVR_Logout_V30(lUserID);
//				lUserID = new NativeLong(-1);
            }
            /**
             * 注册设备
             */
            HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();


            log.info("登陆参数: ip="+camera.getIp()+"  port="+camera.getSeverPort()+"  username="+camera.getAccount()+"  password="+camera.getPassword());


            lUserID = hCNetSDK.NET_DVR_Login_V30(camera.getIp(),Short.parseShort(String.valueOf(camera.getSeverPort())), camera.getAccount(),camera.getPassword(), m_strDeviceInfo);


            if (lUserID.longValue() == -1) {

                log.error(camera.getIp() + " 登录失败.");

                throw new Exception(camera.getIp() + " 登录失败.错误类型："+hCNetSDK.NET_DVR_GetLastError());

            }else {

                log.info(camera.getIp() + " 登录成功. 开始抓拍图片");
            }


            /**
             * 登录成功，开始抓图
             */
            NativeLong lChannel = new NativeLong(1);// 通道号 Channel number
            HCNetSDK.NET_DVR_JPEGPARA net_dvr_jpegpara = new HCNetSDK.NET_DVR_JPEGPARA();


            /**
             * 抓拍参数
             * wPicSize     图片尺寸：0-CIF(352*288/352*240)，1-QCIF(176*144/176*120)，2-4CIF(704*576/704*480)或D1(720*576/720*486)，3-UXGA(1600*1200)，
                 4-SVGA(800*600)，5-HD720P(1280*720)，6-VGA(640*480)，7-XVGA(1280*960)，8-HD900P(1600*900)，9-HD1080P(1920*1080)，10-2560*1920，
                 11-1600*304，12-2048*1536，13-2448*2048，14-2448*1200，15-2448*800，16-XGA(1024*768)，17-SXGA(1280*1024)，18-WD1(960*576/960*480),
                 19-1080I(1920*1080)，20-576*576，21-1536*1536，22-1920*1920，0xff-Auto(使用当前码流分辨率)
             wPicQuality    图片质量系数：0-最好，1-较好，2-一般
             */
            net_dvr_jpegpara.wPicSize = (short) 0xff;
            net_dvr_jpegpara.wPicQuality = 2;

            log.info("抓拍参数: lUserID="+lUserID.longValue()+"  lChannel="+lChannel+"  fileName="+imageSavePath +imageName);

            if (hCNetSDK.NET_DVR_CaptureJPEGPicture(lUserID, lChannel,net_dvr_jpegpara, imageSavePath+imageName)) {

                log.info(camera.getIp()+" 抓拍成功.保存在:" + imageSavePath+imageName);

            }else{
                log.info(camera.getIp()+" 抓拍失败.错误类型：" +hCNetSDK.NET_DVR_GetLastError());

                throw new Exception(camera.getIp()+" 抓拍失败.错误类型：" +hCNetSDK.NET_DVR_GetLastError());
            }

        } catch (Exception e) {
            log.error("调用摄像头失败异常.",e);

            throw new Exception(e);

        }finally {

            //退出登录
            if(hCNetSDK!=null && lUserID!=null){
                hCNetSDK.NET_DVR_Logout_V30(lUserID);

                log.info("退出登录完成");
            }
        }

        return imageHost +imageName;
    }

    @Override
    public List<Camera> getAllByUser(int userId) {

        //获取用户对应仓单列表
        //通过用户编号获取仓单编号列表
        List<Receipt> receipts = receiptService.getReceiptsByUser(userId);

        if(receipts==null || receipts.size()==0) return null;

        List<String> receiptNos = receipts.stream().map(Receipt::getNo).collect(Collectors.toList());


        //通过仓单编号获取摄像头列表
        DetachedCriteria where = DetachedCriteria.forClass(CameraReceiptRelation.class);
        where.add(Restrictions.in("receipt.no", receiptNos));

        List<CameraReceiptRelation> relations = cameraReceiptRelationBaseDao.query(where);

        if(relations==null || relations.size()==0) return null;

        //抽取摄像头对象 并去除重复对象
        return relations.stream().map(CameraReceiptRelation::getCamera).distinct().collect(Collectors.toList());
    }

    @Override
    public String captureByAPI(Camera camera) throws Exception {

        String image_url = "";

        //调用萤石云api获取图片访问地址
        String image_ys_url = YSApi.capture(camera.getSerialNumber());

        //如果图片地址不是空， 下载图片到服务器指定地址
        byte[] btImg = GetImage.getImageFromNetByUrl(image_ys_url);

        //定义图片名称
        String imageName = String.valueOf(new Date().getTime()) + ".jpg";

        if ((null != btImg) && (btImg.length > 0)) {

            log.info("读取到：" + btImg.length + " 字节");

            //如果字节太小，重新读取图片
            if(btImg.length < 20000){

                btImg =  GetImage.getImageFromNetByUrl(image_ys_url);
            }

            GetImage.writeImageToDisk(btImg, imageName, imageSavePath);

            log.info(camera.getIp()+" 抓拍成功.保存在:" + imageSavePath+imageName);

            //返回图片本服务器上的访问地址
            image_url = imageHost + imageName;

        } else {
            log.info("没有从该连接获得内容");
        }


        return image_url;
    }


}
